# @Time    : 2022/9/19 14:07
# @Author  : 南黎
# @FileName: C.建立逻辑回归模型.py

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from prettytable import PrettyTable
from sklearn import preprocessing
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.model_selection import train_test_split

def load_data():
    data=pd.read_csv("Iris.csv").values

    #1.把第五个y值改成1或0
    for i in range(len(data)):
        if data[i,4]=='setosa':
            data[i,4]=1
        elif data[i,4]=='versicolor':
            data[i,4]=0

    #2.数据归一化
    max_abs_scaler = preprocessing.MaxAbsScaler()#注册一个预处理对象
    data = max_abs_scaler.fit_transform(data)#fit_transform(X[, y])	适合数据，然后转换它。

    #3.切片取得特征值和分类标记
    data_point = data[:, 0:5:2]  # 取得x1，x3,y,这里用到了切片步长，刚刚好1，3，5步长2的切片
    Iris_X=data_point[:,0:2]#取得x1，x3
    Iris_Y=data_point[:,2]#取得y,用1和0表示
    return  Iris_X,Iris_Y.astype('int')#注意一定要让y值加上.astype('int'),否则会报错，对于标本结果必须要是整型。

#1.读取数据
Iris_X,Iris_Y=load_data()

#2.导入数据，test_size=0.2表示训练和测试数据比例为8:2,为了保证每次结果的一致性而把随机数种子设置为0
X_train, X_test, y_train, y_test = train_test_split(Iris_X, np.ravel(Iris_Y),test_size=0.2,random_state=0)
#（1）train_test_split()是交叉验证中常用的数据分割函数，可以把样本中随机的按比例选取train data和testdata
#train_data：所要划分的样本特征集
#train_target：所要划分的样本结果
#test_size：样本占比，如果是整数的话就是样本的数量
#random_state：是随机数的种子。
#（2）np.ravel(Iris_Y) 将多维数组降为一维，返回的是视图，修改时会影响原始矩阵
#简单的一个例子来说就是像这样[[1 , 2] , [3 , 4]]---> [1 2 3 4]，去掉了内部的括号


reg = LogisticRegression(C=1e5, solver='newton-cg',max_iter=1000,fit_intercept=True)
#（3）LogisticRegression 逻辑回归求解函数
#C：浮动，默认值：1.0 正则化强度的倒数；必须是正浮点数。与支持向量机一样，较小的值指定更强的正则化。
#solver：是选择求解器{'newton-cg'，'lbfgs'，'liblinear'，'sag'}，默认值：'liblinear'
#  liblinear：使用了开源的liblinear库实现，内部使用了坐标轴下降法来迭代优化损失函数。
#  lbfgs：拟牛顿法的一种，利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
#  newton-cg：也是牛顿法家族的一种，利用损失函数二阶导数矩阵即海森矩阵来迭代优化损失函数。
#  sag：即随机平均梯度下降，是梯度下降法的变种，和普通梯度下降法的区别是每次迭代仅仅用一部分的样本来计算梯度，适合于样本数据多的时候。
#  saga：线性收敛的随机优化算法的的变重。
#max_iter：整数，默认值：100仅对 newton-cg、sag 和 lbfgs 求解器有用。求解器收敛的最大迭代次数。
#fit_intercept：布尔值，默认值 真：指定是否应将常数（也称为偏差或截距）添加到决策函数中。

#3.训练模型
reg.fit(X_train,y_train)
#reg.fit，参数是样本特征集和样本结果集，X_train和y_train

#4.测试模型
y_pred=reg.predict(X_test)
print('test accuracy:\n',accuracy_score(y_test,y_pred))  #打印模型精度
print('weights:\n', reg.coef_, '\nbias:\n', reg.intercept_)  #打印模型参数
pre=reg.predict(Iris_X)#使用特征x预测结果y
cm = confusion_matrix(Iris_Y, pre)#计算混淆矩阵
print("confusion_matrix:")   #打印混淆矩阵
cm_table = PrettyTable(["","predict: 0 class", "predict: 1 class"])#格式化输出
cm_table.add_row(["true: 0 class",cm[0,0], cm[0,1]]);cm_table.add_row(["true: 1 class",cm[1,0], cm[1,1]])
print(cm_table)